package com.gao.api.gate.quick.core.lifecycle;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executor;

public abstract class AbstractLifecycle implements Lifecycle {

    protected static final Logger log = LoggerFactory.getLogger(AbstractLifecycle.class);

    private final List<LifecycleListener> lifecycleListeners = new CopyOnWriteArrayList<>();

    private volatile LifecycleState state = LifecycleState.NEW;

    private boolean throwOnFailure = true;

    public boolean getThrowOnFailure() {
        return throwOnFailure;
    }

    public void setThrowOnFailure(boolean throwOnFailure) {
        this.throwOnFailure = throwOnFailure;
    }

    @Override
    public void addListener(LifecycleListener listener) {
        lifecycleListeners.add(listener);
    }

    @Override
    public List<LifecycleListener> getListener() {
        return lifecycleListeners;
    }

    @Override
    public void removeListener(LifecycleListener listener) {
        lifecycleListeners.remove(listener);
    }

    protected void fireLifecycleEvent(LifecycleState state, Object data) {
        LifecycleEvent event = new LifecycleEvent(this, state, data);
        for (LifecycleListener listener : lifecycleListeners) {
            listener.lifecycleEvent(event);
        }
    }

    @Override
    public final synchronized void init() throws LifecycleException {
        log.info("[{}] lifecycle [init] ",getServiceName());
        // 非就绪状态
        if (!state.equals(LifecycleState.NEW)) {
            invalidTransition("init");
        }

        try {
            setStateInternal(LifecycleState.INITIATING, null);
            initInternal();
        } catch (Throwable t) {
            handleSubClassException(t, "Failed to initialize component [{}]", toString());
        }
    }


    protected abstract void initInternal() throws LifecycleException;


    @Override
    public final synchronized void start() throws LifecycleException {
        if (LifecycleState.STARTING_PREP.equals(state)  ||
                LifecycleState.STARTED.equals(state)) {
            log.info("The start() method was called on component [{}] after start() had already been called. The second call will be ignored.", toString());
            return;
        }

        if (state.equals(LifecycleState.NEW)) { // 如果没有初始化就先初始化
            init();
        } else if (state.equals(LifecycleState.FAILED)) { // 如果为失败状态就停止
            stop();
        } else if (!state.equals(LifecycleState.INITIATING)) {
            invalidTransition("start");
        }

        try {
            log.info("[{}] lifecycle [start] ",getServiceName());
            setStateInternal(LifecycleState.STARTING_PREP, null);
            startInternal();
            if (state.equals(LifecycleState.FAILED)) {
                stop();
            }  else {
                setStateInternal(LifecycleState.STARTED, null);
            }
        } catch (Throwable t) {
            handleSubClassException(t, "Failed to start component [{}]", toString());
        }
    }


    protected abstract void startInternal() throws LifecycleException;


    @Override
    public final synchronized void stop() throws LifecycleException {

        log.info("[{}] lifecycle [stop] ",getServiceName());

        if (LifecycleState.STOPPING_PREP.equals(state) ||
                LifecycleState.STOPPED.equals(state)) {
            log.info("The stop() method was called on component [{}] after stop() had already been called. The second call will be ignored.", toString());
            return;
        }

        if (state.equals(LifecycleState.NEW)) {
            state = LifecycleState.STOPPED;
            return;
        }

        if (!state.equals(LifecycleState.STARTED) && !state.equals(LifecycleState.FAILED)) {
            invalidTransition("stop");
        }

        try {

            setStateInternal(LifecycleState.STOPPING_PREP, null);

            stopInternal();

            setStateInternal(LifecycleState.STOPPED, null);
        } catch (Throwable t) {
            handleSubClassException(t, "Failed to stop component [{}]", toString());
        }
    }


    protected abstract void stopInternal() throws LifecycleException;

    protected abstract String getServiceName();


    @Override
    public LifecycleState getCurrentState() {
        return state;
    }


    protected synchronized void setState(LifecycleState state) throws LifecycleException {
        setStateInternal(state, null);
    }


    protected synchronized void setState(LifecycleState state, Object data)
            throws LifecycleException {
        setStateInternal(state, data);
    }


    private synchronized void setStateInternal(LifecycleState state, Object data)
            throws LifecycleException {
        this.state = state;
        if (state != null) {
            fireLifecycleEvent(state, data);
        }
    }


    private void invalidTransition(String type) throws LifecycleException {
        String msg = "An invalid Lifecycle transition was attempted ([" + type + "]) for component [" + toString() + "] in state [" + state + "]";

        throw new LifecycleException(msg);
    }


    private void handleSubClassException(Throwable t, String msg, Object... args) throws LifecycleException {
        setStateInternal(LifecycleState.FAILED, null);
        ExceptionUtils.handleThrowable(t);
        if (getThrowOnFailure()) {
            if (!(t instanceof LifecycleException)) {
                t = new LifecycleException(msg, t);
            }
            throw (LifecycleException) t;
        } else {
            log.error(msg, args, t);
        }
    }
}
